package com.dmall.promotion.useraop.aspect;

import com.dmall.promotion.annotation.UserOperation;
import com.dmall.promotion.enums.UserOperationEnum;
import com.dmall.promotion.useraop.event.UserOperationEvent;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 用户操作切面
 * 拦截添加了 @UserOperation 注解的方法
 * @author xiao1.wang
 * @date 2021-06-03 21:57:05
 */
@Component
@Aspect
@Slf4j
public class UserOperationAspect implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Pointcut("@annotation(com.dmall.promotion.annotation.UserOperation)")
    public void userOperationPointcut() {
    }

    /**
     * 必须是后置通知，需要拿方法的返回值
     * @param joinPoint 切入点对象
     * @param retValue 方法返回值
     */
    @AfterReturning(value = "userOperationPointcut()", returning = "retValue")
    public void userOperateAfterReturning(JoinPoint joinPoint, Object retValue) {
        try {
            Object[] objects = joinPoint.getArgs();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            UserOperation annotation = method.getAnnotation(UserOperation.class);
            UserOperationEnum operationEnum = annotation.value();
            // 创建事件对象
            UserOperationEvent event = new UserOperationEvent(applicationContext);
            event.setParams(objects);
            event.setResult(retValue);
            event.setOperation(operationEnum);
            // 发布事件对象
            applicationContext.publishEvent(event);
        } catch (Exception e) {
            log.error("UserOperationAspect#userOperateAfterReturning 切面方法抛异常了", e);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
